#import "DataUtils.h"

#import <sys/utsname.h>
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#import <netdb.h>
#import <SystemConfiguration/SCNetworkReachability.h>
#import <AVFoundation/AVFoundation.h>
#import <CommonCrypto/CommonDigest.h>

@implementation DataUtils

+ (NSString*)appName {
    return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
}

// judge network is available
+ (BOOL)isConnectedToNetwork {
    // Create zero addy
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;
    
    // Recover reachability flags
    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress);
    SCNetworkReachabilityFlags flags;
    
    BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
    CFRelease(defaultRouteReachability);
    
    if (!didRetrieveFlags) {
        NSLog(@"Error. Could not recover network reachability flags");
        return NO;
    }
    
    return ((flags & kSCNetworkFlagsReachable) && !(flags & kSCNetworkFlagsConnectionRequired)) ? YES : NO;
}

+ (BOOL)isConnectedToWiFi {
   	struct sockaddr_in localWifiAddress;
    bzero(&localWifiAddress, sizeof(localWifiAddress));
    localWifiAddress.sin_len = sizeof(localWifiAddress);
    localWifiAddress.sin_family = AF_INET;
    // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
    localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
    
    SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)&localWifiAddress);
    SCNetworkReachabilityFlags flags;
    
    BOOL didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags);
    CFRelease(defaultRouteReachability);
    
    if (!didRetrieveFlags) {
        NSLog(@"Error. Could not recover network reachability flags");
        return NO;
    }
    
    return ((flags & kSCNetworkReachabilityFlagsReachable)&&(flags & kSCNetworkReachabilityFlagsIsDirect)) ? YES : NO;
}

+ (NSString *)networkName {
    if ([self isConnectedToNetwork]) {
        if ([self isConnectedToWiFi]) {
            return @"WiFi";
        } else {
            return @"3G/GPRS";
        }
    } else {
        return @"Not Connect NetWork";
    }
}

+ (NSString *)platformName {
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString* platform = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
    if ([platform hasPrefix:@"iPhone"]) {
        return @"iPhone";
    } else if ([platform hasPrefix:@"iPad"]) {
        return @"iPad";
    } else if ([platform hasPrefix:@"iPod"]) {
        return @"iPod Touch";
    }
    return platform;
}

+ (BOOL)isValidPassword:(NSString *)password {
    if ([password length] >= 6 && [password length] < 25) {
        return YES;
    }
    
    return NO;
}

+ (BOOL)isSamePassword:(NSString *)password withRepeatPassword:(NSString *)repeatPassword {
    if([password compare:repeatPassword] == NSOrderedSame)
        return YES;
    else
        return NO;
}

+ (BOOL)isValidEmail:(NSString *)email {
    BOOL valid = YES;
    
    NSError *error = NULL;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[A-Z0-9_.%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$"
                                                                           options:NSRegularExpressionCaseInsensitive
                                                                             error:&error];
    
    if (regex) {
        NSUInteger num = [regex numberOfMatchesInString:email options:NSMatchingReportCompletion range:NSMakeRange(0, [email length])];
        if (num == 0) {
            valid = NO;
        }
    }
    
    if ([email length] >= 50) {
        valid = NO;
    }
    return valid;
}

+ (BOOL)isValidMobliePhoneNumber:(NSString *)mpNumber {
    BOOL valid = YES;
    
    NSError *error = NULL;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^1\\d{9}\\d$"
                                                                           options:NSRegularExpressionCaseInsensitive
                                                                             error:&error];
    
    if (regex) {
        NSUInteger num = [regex numberOfMatchesInString:mpNumber
                                                options:NSMatchingReportCompletion
                                                  range:NSMakeRange(0, [mpNumber length])];
        if (num == 0) {
            valid = NO;
        }
    }
    
    return valid;
}

+ (BOOL)isValidBirthday:(NSString*)birthday {
    BOOL valid = YES;
    
    if (birthday == nil)
        valid = NO;
    
    return valid;
}

+ (BOOL)isValidScreenName:(NSString*)screenName {
    BOOL valid = NO;
    NSString *name = [screenName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    NSInteger length = [name length];
    if (length > 0 && length <= 10) {
        valid = YES;
    }
    
    return valid;
}

+ (NSString *)fileSizeConvertToString:(unsigned long long)fileSizeBits {
    NSString *size;
    if (fileSizeBits < 1000 * 1000) {
        size = [NSString stringWithFormat:@"%.3gK", fileSizeBits / 1000 * 1.0];
    } else if (fileSizeBits >= 1000 * 1000 && fileSizeBits < 1000 * 1000 * 1000) {
        size = [NSString stringWithFormat:@"%.3gM", fileSizeBits / (1000 * 1000) * 1.0];
    } else {
        size = [NSString stringWithFormat:@"%.3gG", fileSizeBits / (1000 * 1000 * 1000) * 1.0];
    }
    
    return size;
}

+ (unsigned long long)fileSize:(NSString *)file {
    NSDictionary *attributeOfFile = [[NSFileManager defaultManager] attributesOfItemAtPath:file error:nil];
    return attributeOfFile ? [[attributeOfFile objectForKey:@"NSFileSize"] unsignedLongLongValue] : 0;
}

+ (NSString *)tmpDirectory {
    return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
}

+ (NSString *)cachesDirectory {
    return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
}

+ (void)ensureDirectoryExist:(NSString *)dirPath {
    NSFileManager* fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:dirPath]) {
        [fileManager createDirectoryAtPath:dirPath
               withIntermediateDirectories:YES
                                attributes:nil
                                     error:nil];
    }
}

+ (NSDate*)fileModificationDate:(NSString*)filePath {
    return [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil] objectForKey:NSFileModificationDate];
}

+ (BOOL)hasEnoughFreeDiskspace {
    BOOL isEnough = YES;
    NSDictionary *attribute = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[self tmpDirectory] error:nil];
    
    if (attribute) {
        NSNumber *freeFileSystemSizeInBytes = [attribute objectForKey:NSFileSystemFreeSize];
        unsigned long long freeSize = [freeFileSystemSizeInBytes unsignedLongLongValue];
        if (freeSize < 50 * 1024 * 1024) {
            isEnough = NO;
        }
    }
    
    return isEnough;
}

+ (BOOL)isURLEscapeCharacter:(unichar)c {
    switch (c) {
        case ' ':
        case '#':
        case '$':
        case '%':
        case '&':
        case '@':
        case '`':
        case '/':
        case ':':
        case ';':
        case '<':
        case '=':
        case '>':
        case '?':
        case '[':
        case '\\':
        case ']':
        case '^':
        case '{':
        case '|':
        case '}':
        case '\"':
        case '+':
        case ',':
            return YES;
            
        default:
            return NO;
    }
    return NO;
}

+ (NSString*)escapeURLCharacter:(unichar)c {
    switch (c) {
        case ' ':
            return @"%20";
            
        case '#':
            return @"%23";
            
        case '$':
            return @"%24";
            
        case '%':
            return @"%25";
            
        case '&':
            return @"%26";
            
        case '@':
            return @"%40";
            
        case '`':
            return @"%60";
            
        case '/':
            return @"%2F";
            
        case ':':
            return @"%3A";
            
        case ';':
            return @"%3B";
            
        case '<':
            return @"%3C";
            
        case '=':
            return @"%3D";
            
        case '>':
            return @"%3E";
            
        case '?':
            return @"%3F";
            
        case '[':
            return @"%5B";
            
        case '\\':
            return @"%5C";
            
        case ']':
            return @"%5D";
            
        case '^':
            return @"%5E";
            
        case '{':
            return @"%7B";
            
        case '|':
            return @"%7C";
            
        case '}':
            return @"%7D";
            
        case '\"':
            return @"%22";
            
        case '+':
            return @"%2B";
            
        case ',':
            return @"%2C";
            
        default:
            return [NSString stringWithCharacters:&c length:1];
    }
    return nil;
}

+ (BOOL)haveURLEscapeCharacter:(NSString *)s {
    for (NSUInteger i = 0; i < [s length]; ++i) {
        if ([self isURLEscapeCharacter:[s characterAtIndex:i]]) {
            return YES;
        }
    }
    return NO;
}

+ (NSString *)escapeURLString:(NSString*)s {
    if (![self haveURLEscapeCharacter:s]) {
        return s;
    }
    else {
        NSString* ns = [[NSString alloc] init];
        for (NSUInteger i = 0; i < [s length]; ++i) {
            ns = [ns stringByAppendingString:[self escapeURLCharacter:[s characterAtIndex:i]]];
        }
        return ns;
    }
    return nil;
}

+ (NSString *)escapeURLStringWithoutPercentChar:(NSString *)s {
    if (![self haveURLEscapeCharacter:s]) {
        return s;
    }
    else {
        NSString* ns = [[NSString alloc] init];
        for (NSUInteger i = 0; i < [s length]; ++i) {
            if ([s characterAtIndex:i] != '%') {
                ns = [ns stringByAppendingString:[self escapeURLCharacter:[s characterAtIndex:i]]];
            }
            else {
                ns = [ns stringByAppendingString:@"%"];
            }
        }
        return ns;
    }
    return nil;
}

+ (NSString *)stringOfTimeZone {
    NSInteger timeZoneSeconds = [[NSTimeZone localTimeZone] secondsFromGMT];
    NSInteger timeZoneHours = timeZoneSeconds / 3600;
    NSInteger timeZoneMins = (timeZoneSeconds - timeZoneHours * 3600) / 60;
    
    NSString *signMark;
    if (timeZoneHours >= 0) {
        signMark = @"%2B";
    }
    else {
        timeZoneHours = -timeZoneHours;
        signMark = @"-";
    }
    
    if (timeZoneMins < 0) {
        timeZoneMins = -timeZoneMins;
    }
    NSString *timeZoneText = [NSString stringWithFormat:@"%@%02d%02d", signMark, (int)timeZoneHours, (int)timeZoneMins];
    return timeZoneText;
}

+ (BOOL)isTimeFormatVideoTitle:(NSString *)videoTitle {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];//NSGregorianCalendar];
    [dateFormatter setCalendar:calendar];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    
    NSDate * date = [dateFormatter dateFromString:videoTitle];
    return date != nil ? YES : NO;
}

+ (NSString *)yyyyMMddHHmmssLocalTime {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];//NSGregorianCalendar];
    [dateFormatter setCalendar:calendar];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSString* localTime = [dateFormatter stringFromDate:[NSDate date]];
    return localTime;
}

+ (NSTimeInterval)yyyyMMddHHmmssToSecondsSince1970:(NSString *)dateString {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];//NSGregorianCalendar];
    [dateFormatter setCalendar:calendar];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    return [[dateFormatter dateFromString:dateString] timeIntervalSince1970];
}

+ (NSString *)defaultUserAgentString {
    NSBundle *bundle = [NSBundle mainBundle];
    NSString *appName = [bundle objectForInfoDictionaryKey:@"CFBundleName"];
    UIDevice *device = [UIDevice currentDevice];
    // Takes the form "My Application 1.0 (Macintosh; Mac OS X 10.5.7; en_GB)"
    return [NSString stringWithFormat:@"%@ %@ (%@; %@ %@; %@)",
            appName,
            [self appVersion],
            [device model],
            [device systemName],
            [device systemVersion],
            [NSLocale currentLocale].localeIdentifier];
}

+ (NSString *)appVersion {
    NSBundle *bundle = [NSBundle mainBundle];
    NSString *appVersion = nil;
    NSString *marketingVersionNumber = [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
    NSString *developmentVersionNumber = [bundle objectForInfoDictionaryKey:@"CFBundleVersion"];
    if (marketingVersionNumber && developmentVersionNumber) {
        if ([marketingVersionNumber isEqualToString:developmentVersionNumber]) {
            appVersion = marketingVersionNumber;
        } else {
            appVersion = [NSString stringWithFormat:@"%@ rv:%@",marketingVersionNumber,developmentVersionNumber];
        }
    } else {
        appVersion = (marketingVersionNumber ? marketingVersionNumber : developmentVersionNumber);
    }
    return appVersion;
}

+ (NSString*)hexText:(NSString*)userId {
    char hexs[512] = {0};
    const char* s = [userId UTF8String];
    for (char* phexs = hexs; s && *s != 0 && phexs < hexs + 510; ++s, phexs += 2) {
        sprintf(phexs, "%02x", *s);
    }
    return [NSString stringWithFormat:@"%s", hexs];
}

+ (BOOL)isValidAccessToken:(NSString*)error {
    if (error && [error compare:@"AK-10"] == NSOrderedSame) {
        return NO;
    }
    return YES;
}

+ (NSString*)createUUID {
    CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
    NSString *suuid = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuid);
    CFRelease(uuid);
    return suuid;
}

+ (NSString*)createUUIDRawBytes {
    CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
    CFUUIDBytes bytes = CFUUIDGetUUIDBytes(uuid);
    CFRelease(uuid);
    return [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
            bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, bytes.byte4, bytes.byte5, bytes.byte6, bytes.byte7,
            bytes.byte8, bytes.byte9, bytes.byte10, bytes.byte11, bytes.byte12, bytes.byte13, bytes.byte14, bytes.byte15];
}

+ (NSString*)uuid2RawBytes:(NSUUID*)uuid {
    uuid_t bytes;
    [uuid getUUIDBytes:bytes];
    return [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
            bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]];
}

+ (BOOL)isValidPid:(NSNumber*)pid {
    return pid.integerValue > 0;
}

+ (NSComparisonResult)compareVersion:(NSString*)version toVersion:(NSString*)toVersion {
    return [version compare:toVersion options:NSNumericSearch];
}


# pragma mark - hash helpers
+ (NSString *)md5HexDigest:(NSString *)code {
    NSData* inputData = [code dataUsingEncoding:NSUTF8StringEncoding];
    unsigned char outputData[CC_MD5_DIGEST_LENGTH];
    CC_MD5([inputData bytes], (uint32_t)[inputData length], outputData);
    
    NSMutableString* hashStr = [NSMutableString string];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; ++i)
        [hashStr appendFormat:@"%02x", outputData[i]];
    
    return hashStr;
}

@end
